//
//  Events.swift
//  LocationTrackerAdmin
//
//  Created by mac on 2025/2/19.
//

import Vapor
import Fluent
import Queues
import FluentKit
struct Events: RouteCollection {
    func boot(routes: any RoutesBuilder) throws {
        let events = routes.grouped("events")
        events
            .post("sos", use: self.sos)
        events
            .post("driveMonitor", use: self.beginDriveMonitor)
        events
            .post("isHaveDriveMonitor", use: self.isHaveDriveMonitor)
        events
            .post("endDriveMonitor", use: self.endDriveMonitor)
        events
            .get("eventsCountWithinMonth", use: self.eventsCountWithinMonth)
        events
            .post("beginDriveMonitor", use: self.beginDriveMonitor)
        events
            .post("addTask", use: self.addTask)
        events
            .post("updateTask", use: self.modifyTask)
        events
            .post("endTask", use: self.endsTask)
        events
            .get("getAllEventKind", use: self.getAllKindOfEventReadState)
        events
            .get("getEvents", use: self.getEventList)
        events
            .get("getEventDetail", use: self.getEventDetail)
        events
            .get("getEventDetailById", use: self.getEventDetailById)
    }
    
    //获取本月保护驾驶次数，本月碰撞检测次数
    struct EventCountData: Content {
        let protectDriveCount: Int
        let collsionCount: Int
    }
    @Sendable
    func eventsCountWithinMonth(request: Request) async throws -> JSONResponse<EventCountData> {
        let headers = request.headers
        let deviceID = headers["did"].first ?? ""
        //查询事故任务以及碰撞检测次数
        let protectCount = try await TaskModel.query(on: request.db)
            .filter(\.$monitoredID, .equal, deviceID)
            .filter(\.$type, .equal, 3)
            .filter(\.$status, .equal, 2)
            .count() //保护驾驶次数
        let collisionCount = try await TaskModel.query(on: request.db)
            .filter(\.$monitoredID, .equal, deviceID)
            .filter(\.$type, .equal, 3)
            .filter(\.$collisionOccured, .equal, true)
            .count() //碰撞次数
        return JSONResponse(message: "", code: 0, data: EventCountData(
            protectDriveCount: protectCount, collsionCount: collisionCount
        ))
    }
    
    //发送sos信号给圈子里的人
    struct SOSParam: Content {
        let latitude: Double
        let longitude: Double
        let detail: String
    }
    
    @Sendable
    func sos(request: Request) async throws -> JSONResponse<Bool> {
        let param = try request.content.decode(SOSParam.self)
        let headers = request.headers
        let initiatorID = headers["did"].first ?? ""
        guard let user = try await UserModel.query(on: request.db)
            .filter(\.$id == initiatorID)
            .first() else {
            return JSONResponse(message: "用户不存在", code: -1, data: false)
        }
        let userGroups = try await GroupMemberModel.query(on: request.db)
            .filter(\.$memberID == initiatorID)
            .with(\.$group)
            .all()
        let groupIds = userGroups.map { $0.group.id! }
        let groupMembers = try await GroupMemberModel.query(on: request.db)
            .filter(\.$group.$id ~~ groupIds)
            .filter(\.$memberID != initiatorID)
            .all()
        let memberIds = groupMembers.map { $0.memberID }
        // Create SOS task
        let task = TaskModel(
            id: UUID().uuidString,
            initiatorID: initiatorID,
            monitoredID: initiatorID,
            createDate: Date(),
            groupId: nil,  // Associate with first group
            updateDate: Date(),
            status: 2,
            type: 4,
            collisionOccured: false,
            locationsWhenTaskOccured: [
                TaskModel.LocationWhenTaskOccured(
                    latitude: param.latitude,
                    longitude: param.longitude,
                    detail: param.detail,
                    date: Date()
                )
            ]
        )
        let apnsTokens = try await APNSModel.query(on: request.db)
            .filter(\.$deviceID ~~ memberIds)
            .all()
        let tokens = apnsTokens.map { $0.token }
        try await request.queue.dispatch(PushJob.self, PushJob.Payload(receivers: tokens, eventId: task.id!, title: "\(user.name)发起紧急求助，请立即查看!", body: "点击立即查看", avatar: user.avatar, mutableContent: true))
        try await task.save(on: request.db)
        return JSONResponse(
            message: "SOS发送成功，已通知您所在群组的所有成员",
            code: 0,
            data: true
        )
    }
    
    //是否已有一个驾驶监控事件
    @Sendable
    func isHaveDriveMonitor(request: Request) async throws -> JSONResponse<Bool>{
        let headers = request.headers
        let deviceID = headers["did"].first ?? ""
        let protectCount = try await TaskModel.query(on: request.db)
            .filter(\.$monitoredID, .equal, deviceID)
            .filter(\.$type, .equal, 3)
            .filter(\.$status, .equal, 1)
            .count() //保护驾驶次数
        return JSONResponse(message: "", code: 0, data: protectCount > 0)
    }
    
    //开启一个驾驶监控
    @Sendable
    func beginDriveMonitor(request: Request) async throws -> JSONResponse<Bool> {
        struct BeginDriveParam: Content {
            let time: String
        }//截止时间
        let param = try request.content.decode(BeginDriveParam.self)
        let headers = request.headers
        let initiatorID = headers["did"].first ?? ""
        let protectCount = try await TaskModel.query(on: request.db)
            .filter(\.$monitoredID, .equal, initiatorID)
            .filter(\.$type, .equal, 3)
            .filter(\.$status, .equal, 1)
            .count() //保护驾驶次数
        if (protectCount > 0) {
            return JSONResponse(message: "当前已有驾驶监控事件，请先结束", code: 0, data: true)
        }
        let formatter = DateFormatter()
        formatter.dateFormat = "YYYY-MM-DD HH:mm:ss"
        formatter.timeZone = TimeZone(secondsFromGMT: 8 * 3600)
        let expire = formatter.date(from: param.time)
        let task = TaskModel(id: UUID().uuidString, initiatorID: initiatorID, monitoredID: initiatorID, createDate: Date(), groupId: nil,updateDate: Date(), expiryDate: expire ,status: 1, type: 3, collisionOccured: false, locationsWhenTaskOccured: [])
        try await task.save(on: request.db)
        try await request.queue.dispatch(EndWatchDriveJob.self, EndWatchDriveJob.Payload(eventId: task.id!))
        return JSONResponse(message: "添加驾驶监控成功", code: 0, data: true)
    }
    //结束一个驾驶监控事件
    @Sendable
    func endDriveMonitor(request: Request) async throws -> JSONResponse<Bool> {
        let headers = request.headers
        let deviceID = headers["did"].first ?? ""
        guard let task = try await TaskModel.query(on: request.db)
            .filter(\.$monitoredID == deviceID)
            .filter(\.$initiatorID == deviceID)
            .filter(\.$type == 3) // driving monitor type
            .filter(\.$status != 3) // active status
            .first() else {
                return JSONResponse(
                    message: "未找到进行中的驾驶监控事件",
                    code: -1,
                    data: false
                )
            }
        
        // Update task status to completed
        task.status = 3 // completed status
        task.updateDate = Date()
        
        try await task.save(on: request.db)
        
        return JSONResponse(
            message: "驾驶监控已结束",
            code: 0,
            data: true
        )
    }
    
    @Sendable
    func addTask(request: Request) async throws -> JSONResponse<String> {
        struct AddFenceParam: Content {
            let id: String        // 被监控者ID
            let type: Int        //  任务类型：0越界 1进入 2未达 3事故
            let fence: [TaskModel.FenceData]
            let endDate: TimeInterval?  // 可选的结束日期
            let groupId: String
        }
        
        let headers = request.headers
        let initiatorID = headers["did"].first ?? ""
        let param = try request.content.decode(AddFenceParam.self)
        //该群组管理员
        let isVIP = try await UserModel.query(on: request.db)
            .filter(\.$id == initiatorID)
            .first()?.isVIP ?? false
        let sandBox = Environment.get("SanxBox") == "1"
        if isVIP == false && sandBox == false {
            let count = param.fence.count
            if count > 1 {
                return JSONResponse(message: "非VIP会员仅能添加一处地理围栏", code: -2, data: "")
            }
        }
        // 验证任务类型
        guard param.type >= 0 && param.type <= 3 else {
            return JSONResponse(
                message: "无效的任务类型",
                code: -1,
                data: ""
            )
        }
        
        // 验证围栏数据（对于类型0,1,2需要围栏数据）
        if param.type <= 2 && param.fence.isEmpty {
            return JSONResponse(
                message: "围栏数据不能为空",
                code: -1,
                data: ""
            )
        }
        
        // 解析结束日期（如果有）
        var expireDate: Date? = nil
        if param.endDate != nil && param.type == 2 {
            expireDate = Date(timeIntervalSince1970: param.endDate!)
        }
        
        // 转换围栏数据
        let fenceData = param.fence
        //检查一下有没有那个群组
        let group = try await GroupModel.query(on: request.db)
            .filter(\.$id == param.groupId)
            .first()
        if group == nil {
            return JSONResponse(
                message: "添加失败,无效的群组",
                code: -1,
                data: nil
            )
        }
        // 创建新任务
        let task = TaskModel(
            id: UUID().uuidString,
            initiatorID: initiatorID,
            monitoredID: param.id,
            createDate: Date(),
            groupId: param.groupId,
            updateDate: Date(),
            expiryDate: expireDate,
            status: 1,          // 1表示生效
            type: param.type,
            fenceData: fenceData,
            collisionOccured: false,
            locationsWhenTaskOccured: []
        )
        
        // 保存任务
        try await task.save(on: request.db)
        
        // 如果设置了结束时间，创建定时任务
        if let expiry = expireDate {
            //未达任务
            try await request.queue.dispatch(
                EndWatchDriveJob.self,
                EndWatchDriveJob.Payload(eventId: task.id!),
                maxRetryCount: 1,
                delayUntil: expiry,
                id: JobIdentifier(string: task.id!)
            )
        }
        
        var taskTypeString = ""
        switch param.type {
            case 0: taskTypeString = "越界监测"
            case 1: taskTypeString = "进入区域监测"
            case 2: taskTypeString = "未达监测"
            case 3: taskTypeString = "事故监测"
            default: taskTypeString = "未知类型"
        }
        
        return JSONResponse(
            message: "添加\(taskTypeString)成功",
            code: 0,
            data: task.id ?? ""
        )
    }
    
    //修改一个越界监测任务
    @Sendable
    func modifyTask(request: Request) async throws -> JSONResponse<Bool> {
        struct ModifyTaskParam: Content {
            let id: String        // 任务ID
            let fence: [TaskModel.FenceData]
            let endDate: TimeInterval?  // 可选的结束日期
        }
        
        let headers = request.headers
        let initiatorID = headers["did"].first ?? ""
        let param = try request.content.decode(ModifyTaskParam.self)
        let isVIP = try await UserModel.query(on: request.db)
            .filter(\.$id == initiatorID)
            .first()?.isVIP ?? false
        let sandBox = Environment.get("SanxBox") == "1"
        if isVIP == false && sandBox == false {
            let count = param.fence.count
            if count > 1 {
                return JSONResponse(message: "非VIP会员仅能添加一处地理围栏", code: -2, data: false)
            }
        }
        // 1. 查找并验证任务
        guard let task = try await TaskModel.query(on: request.db)
            .filter(\.$id == param.id)
            .filter(\.$initiatorID == initiatorID)
            .first() else {
            return JSONResponse(
                message: "未找到该任务或您无权修改",
                code: -1,
                data: false
            )
        }
        
        // 2. 检查任务状态
        guard task.status != 3 else {
            return JSONResponse(
                message: "只能修改进行中的任务",
                code: -1,
                data: false
            )
        }
        
        // 3. 处理新的结束日期
        if let endDate = param.endDate {
            if task.type == 2 {
                let date = Date(timeIntervalSince1970: endDate)
                // 更新结束时间
                task.expiryDate = date
                // 更新定时任务
                request.queue.clear(JobIdentifier(string: param.id))
                    .whenSuccess { _ in
                        
                    }
                try await request.queue.dispatch(
                    EndWatchDriveJob.self,
                    EndWatchDriveJob.Payload(eventId: task.id!),
                    maxRetryCount: 1,
                    delayUntil: date
                )
            }
        }
        
        // 4. 更新围栏数据（如果任务类型需要）
        if task.type <= 2 { // 越界、进入区域、未达类型的任务
            guard !param.fence.isEmpty else {
                task.updateDate = Date()
                task.status = 3
                task.fenceData = nil
                try await task.save(on: request.db)
                return JSONResponse(
                    message: "任务删除成功",
                    code: 0,
                    data: true
                )
            }
            
            let fenceData = param.fence
            task.fenceData = fenceData
        }
        let fenceData = param.fence
        task.fenceData = fenceData
        // 5. 更新修改时间
        task.updateDate = Date()
        // 6. 保存更改
        try await task.save(on: request.db)
        
        // 7. 返回成功响应
        var taskTypeString = ""
        switch task.type {
            case 0: taskTypeString = "越界监测"
            case 1: taskTypeString = "进入区域监测"
            case 2: taskTypeString = "未达监测"
            case 3: taskTypeString = "事故监测"
            default: taskTypeString = "未知类型"
        }
        
        return JSONResponse(
            message: "修改\(taskTypeString)任务成功",
            code: 0,
            data: true
        )
    }
    
    //结束一个越界监测任务
    @Sendable
    func endsTask(request: Request) async throws -> JSONResponse<Bool> {
        struct EndTaskParam: Content {
            let id: String // 任务ID
        }
        
        let headers = request.headers
        let deviceID = headers["did"].first ?? ""
        let param = try request.content.decode(EndTaskParam.self)
        
        // 1. 查找并验证任务
        guard let task = try await TaskModel.query(on: request.db)
            .filter(\.$id == param.id)
            .filter(\.$initiatorID == deviceID)
            .first() else {
            return JSONResponse(
                message: "未找到该任务或您无权结束",
                code: -1,
                data: false
            )
        }
        
        // 2. 检查任务状态
        guard task.status != 3 else {
            return JSONResponse(
                message: "只能结束进行中的任务",
                code: -1,
                data: false
            )
        }
        
        // 3. 如果有定时任务，清除它
        if task.expiryDate != nil {
            request.queue.clear(JobIdentifier(string: task.id!)).whenSuccess { _ in
                
            }
        }
        
        // 4. 更新任务状态
        task.status = 3 // 完成状态
        task.updateDate = Date()
        
        // 5. 保存更改
        try await task.save(on: request.db)
        
        // 6. 返回对应任务类型的成功消息
        var taskTypeString = ""
        switch task.type {
            case 0: taskTypeString = "越界监测"
            case 1: taskTypeString = "进入区域监测"
            case 2: taskTypeString = "未达监测"
            case 3: taskTypeString = "事故监测"
            default: taskTypeString = "未知类型"
        }
        
        return JSONResponse(
            message: "\(taskTypeString)任务已结束",
            code: 0,
            data: true
        )
    }
    
    //获取SOS，事故，越界，已达，未达是否有未读事件
    struct EventsReadState: Content {
        let code: Int
        let title: String
        let haveNew: Bool
    }
    @Sendable
    func getAllKindOfEventReadState(request: Request) async throws -> JSONResponse<[EventsReadState]> {
        let headers = request.headers
        let deviceID = headers["did"].first ?? ""
        let groupMembers = try await GroupMemberModel.query(on: request.db)
            .filter(\.$memberID == deviceID)
            .all()
        let groupIds = groupMembers.map { $0.$group.id }
        // 2. 获取同组用户
        let sameGroupMembers = try await GroupMemberModel.query(on: request.db)
            .filter(\.$group.$id ~~ groupIds)
            .filter(\.$memberID != deviceID)
            .all()
        
        let memberIds = sameGroupMembers.map { $0.memberID }
        
        let tasks = try await TaskModel.query(on: request.db)
            .group(.or, { or in
                or.group(.and) { and in
                    and.filter(\.$initiatorID == deviceID)
                    and.filter(\.$type != 4)//非SOS事件
                }
                or.group(.and) { and in
                    and.filter(\.$initiatorID ~~ memberIds)
                    and.filter(\.$type == 4)//非SOS事件
                }
            })
            .filter(\.$status == 2)//已发生
            .field(\.$type)
            .field(\.$readedUsers)
            .all()
        return JSONResponse(message: "", code: 0, data: [
            EventsReadState(code: 4, title: "SOS", haveNew: tasks.filter({$0.type == 4}).reduce(false, {$0 || !$1.readedUsers.contains(deviceID)})),
            EventsReadState(code: 0, title: "越界", haveNew: tasks.filter({$0.type == 0}).reduce(false, {$0 || !$1.readedUsers.contains(deviceID)})),
            EventsReadState(code: 1, title: "已达", haveNew: tasks.filter({$0.type == 1}).reduce(false, {$0 || !$1.readedUsers.contains(deviceID)})),
            EventsReadState(code: 2, title: "未达", haveNew: tasks.filter({$0.type == 2}).reduce(false, {$0 || !$1.readedUsers.contains(deviceID)})),
        ])
    }
    
    struct EventListData: Content {
        let id: String
        let name: String
        let phone: String
        let date: String
        let avatar: String
        let type: Int
        let readed: Bool
    }
    //获取指定类型的事故列表
    @Sendable
    func getEventList(request: Request) async throws -> JSONResponse<[EventListData]> {
    struct EventListParam: Content {
        let page: Int
        let size: Int
        let type: Int // 0越界 1进入 2 未达 3事故 4SOS
    }
    // 0越界设置 1进入区间 2未达 3事故监测 4SOS
    let headers = request.headers
    let deviceID = headers["did"].first ?? ""
    let param = try request.query.decode(EventListParam.self)
    let groupMembers = try await GroupMemberModel.query(on: request.db)
            .filter(\.$memberID == deviceID)
            .all()
    let groupIds = groupMembers.map { $0.$group.id }
    let sameGroupMembers = try await GroupMemberModel.query(on: request.db)
            .filter(\.$group.$id ~~ groupIds)
            .filter(\.$memberID != deviceID)
            .all()
    let memberIds = sameGroupMembers.map { $0.memberID }
    let tasks = try await TaskModel.query(on: request.db)
        .group(.or, { orGroup in
            orGroup.group(.and) { andGroup in
                andGroup.filter(\.$initiatorID == deviceID)
                andGroup.filter(\.$type != 4)
            }
            orGroup.group(.and) { andGroup in
                andGroup.filter(\.$initiatorID ~~ memberIds)
                andGroup.filter(\.$type == 4)
            }
        })
        .filter(\.$type == param.type)
        .filter(\.$status == 2)
        .sort(\.$createDate, .descending)
        .all()
    
    // 获取被监控用户信息
    let userIds = tasks.map { $0.monitoredID }
    let users = try await UserModel.query(on: request.db)
        .filter(\.$id ~~ userIds)
        .all()
    // 构建返回数据
    let formatter = DateFormatter()
    formatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
    formatter.timeZone = TimeZone(secondsFromGMT: 8 * 3600)
    let eventList = tasks.map { task -> EventListData in
        let user = users.first { $0.id == task.monitoredID }
        return EventListData(
            id: task.id ?? "",
            name: user?.name ?? "",
            phone: user?.phone ?? "",
            date: formatter.string(from: task.createDate),
            avatar: user?.avatar ?? "",
            type: task.type,
            readed: task.readedUsers.contains(deviceID)
        )
    }
    
    return JSONResponse(
        message: "获取事件列表成功",
        code: 0,
        data: eventList
    )
}
    
    //获取事件的详情
    struct EventDetailData: Content {
        let id: String
        let name: String
        let phone: String
        let date: TimeInterval
        let avatar: String
        let type: Int
        let latitude: Double
        let longitude: Double
        let detail: String?
        let fence: [TaskModel.FenceData]
        let expire: TimeInterval?//针对未达事件的过期时间
    }
    @Sendable
func getEventDetail(request: Request) async throws -> JSONResponse<EventDetailData> {
    struct EventDetailParam: Content {
        let id: String//用户id
        let type: Int//事件类型
        let groupId: String//所在群组id
    }
    let headers = request.headers
    let deviceID = headers["did"].first ?? ""
    let param = try request.query.decode(EventDetailParam.self)
    
    // 1. 获取任务详情
    guard let task = try await TaskModel.query(on: request.db)
        .filter(\.$monitoredID == param.id)
        .filter(\.$initiatorID == deviceID)
        .filter(\.$status != 3)
        .filter(\.$groupId == param.groupId)
        .filter(\.$type == param.type)
        .first() else {
        return JSONResponse(
            message: "未找到该事件",
            code: -1,
            data: nil
        )
    }
    
    // 2. 获取用户信息
    guard let user = try await UserModel.query(on: request.db)
        .filter(\.$id == task.monitoredID)
        .first() else {
        return JSONResponse(
            message: "未找到用户信息",
            code: -1,
            data: nil
        )
    }
    
    // 4. 将任务的围栏数据转换为FenceLocation数组
    let fenceLocations = task.fenceData ?? []
    
    // 5. 构建详细数据
    let detailData = EventDetailData(
        id: task.id ?? "",
        name: user.name,
        phone: user.phone,
        date: task.createDate.timeIntervalSince1970,
        avatar: user.avatar,
        type: task.type,
        latitude: user.latitude ?? 0,
        longitude: user.longitude ?? 0,
        detail: user.detail,
        fence: fenceLocations,
        expire: task.expiryDate?.timeIntervalSince1970
    )
    
    // 6. 更新已读状态
    if !task.readedUsers.contains(deviceID) {
        task.readedUsers.append(deviceID)
        try await task.save(on: request.db)
    }
    
    return JSONResponse(
        message: "获取事件详情成功",
        code: 0,
        data: detailData
    )
}
    
    @Sendable
func getEventDetailById(request: Request) async throws -> JSONResponse<EventDetailData> {
    struct EventDetailParam: Content {
        let id: String//事件id
    }
    let headers = request.headers
    let deviceID = headers["did"].first ?? ""
    let param = try request.query.decode(EventDetailParam.self)
    // 1. 获取已触发任务详情
    guard let task = try await TaskModel.query(on: request.db)
        .filter(\.$id == param.id)
        .first() else {
        return JSONResponse(
            message: "未找到该事件",
            code: -1,
            data: nil
        )
    }
    
    // 2. 获取用户信息
    guard let user = try await UserModel.query(on: request.db)
        .filter(\.$id == task.monitoredID)
        .first() else {
        return JSONResponse(
            message: "未找到用户信息",
            code: -1,
            data: nil
        )
    }
    
    // 3. 格式化日期
    let formatter = DateFormatter()
    formatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
    formatter.timeZone = TimeZone(secondsFromGMT: 8 * 3600)
    
    // 4. 将任务的围栏数据转换为FenceLocation数组
    let fenceLocations = task.fenceData ?? []
    
    // 5. 构建详细数据
    if let dtl = task.locationsWhenTaskOccured?.first {
        let detailData = EventDetailData(
            id: task.id ?? "",
            name: user.name,
            phone: user.phone,
            date: dtl.date.timeIntervalSince1970,
            avatar: user.avatar,
            type: task.type,
            latitude: dtl.latitude,
            longitude: dtl.longitude,
            detail: dtl.detail,
            fence: fenceLocations,
            expire: task.expiryDate?.timeIntervalSince1970
        )
        if !task.readedUsers.contains(deviceID) {
            task.readedUsers.append(deviceID)
            try await task.save(on: request.db)
        }
        return JSONResponse(
            message: "获取事件详情成功",
            code: 0,
            data: detailData
        )
    } else {
        return JSONResponse(
            message: "没有查到详情数据",
            code: -1,
            data: nil
        )
    }
}
}
